package com.kaiwu.tc.persistence.session;

import com.kaiwu.tc.persistence.mapping.SqlCommandType;

import java.beans.IntrospectionException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Proxy;
import java.lang.reflect.Type;
import java.sql.SQLException;
import java.util.List;

/**
 * @author Captain
 * @date 2021/1/23
 **/
public class DefaultSqlSession implements SqlSession {

    private Configuration configuration;

    public DefaultSqlSession(Configuration configuration){
        this.configuration = configuration;
    }

    @Override
    public <T> T getMapper(Class<?> className) {

        Object o = Proxy.newProxyInstance(DefaultSqlSession.class.getClassLoader(), new Class[]{className}, (proxy, method, args) -> {

            String statementId = method.getDeclaringClass().getName() + "." + method.getName();
            SqlCommandType sqlCommandType = configuration.getStatementMap().get(statementId).getSqlCommandType();
            switch (sqlCommandType){
                case INSERT:
                case DELETE:
                case UPDATE:
                    return update(statementId, args);
                case SELECT:
                    Type genericReturnType = method.getGenericReturnType();
                    if (genericReturnType instanceof ParameterizedType){
                        return selectList(statementId, args);
                    }
                    return selectOne(statementId, args);
                default:
                   throw new RuntimeException("invalid sqlCommandType");
            }

        });
        return (T) o;
    }

    @Override
    public int update(String statementId, Object... params) throws Exception {
        SimpleExecutor executor = new SimpleExecutor();
        return executor.doUpdate(configuration, configuration.getStatementMap().get(statementId), params);
    }

    @Override
    public <T> List<T> selectList(String statementId, Object... params) throws SQLException, InvocationTargetException, IntrospectionException, InstantiationException, IllegalAccessException, NoSuchFieldException {
        SimpleExecutor executor = new SimpleExecutor();
        return executor.query(configuration, configuration.getStatementMap().get(statementId), params);
    }

    @Override
    public <T> T selectOne(String statementId, Object... params) throws SQLException, IntrospectionException, InstantiationException, IllegalAccessException, NoSuchFieldException, InvocationTargetException {
        List<Object> objects = selectList(statementId, params);
        if (objects.size() == 1) {
            return (T) objects.get(0);
        } else {
            throw new RuntimeException("返回结果过多");
        }
    }

}
